package com.project.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.common.core.domain.entity.SysUser;
import com.common.utils.SecurityUtils;
import com.common.utils.StringUtils;
import com.common.utils.uuid.IdUtils;
import com.project.domain.bo.ProjectBudgetBo;
import com.project.domain.entity.BizProjectBudgetAlteration;
import com.project.domain.entity.BizProjectBudgetBatch;
import com.project.domain.entity.BizProjectBudgetFee;
import com.project.domain.vo.BudgetFeeVo;
import com.project.mapper.ProjectBudgetBatchMapper;
import com.project.mapper.ProjectBudgetFeeMapper;
import com.project.service.IProjectBudgetService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Service
public class ProjectBudgetServiceImpl implements IProjectBudgetService {

    @Autowired
    ProjectBudgetBatchMapper projectBudgetBatchMapper;

    @Autowired
    ProjectBudgetFeeMapper projectBudgetFeeMapper;

    //region 预算主表
    /**
     * 查询项目预算主
     *
     * @param ID 项目预算主主键
     * @return 项目预算主
     */
    @Override
    public BizProjectBudgetBatch selectBizProjectBudgetBatchByID(String ID)
    {
        return projectBudgetBatchMapper.selectById(ID);
    }

    public BizProjectBudgetBatch selectBizProjectBudgetBatch(BizProjectBudgetBatch bizProjectBudgetBatch){
        QueryWrapper<BizProjectBudgetBatch> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(StringUtils.isNotBlank(bizProjectBudgetBatch.getID()),"ID",bizProjectBudgetBatch.getID())
                .eq(StringUtils.isNotBlank(bizProjectBudgetBatch.getProjectId()),"PROJECT_ID",bizProjectBudgetBatch.getProjectId());
        return projectBudgetBatchMapper.selectOne(queryWrapper);
    }

    /**
     * 查询项目预算主列表
     *
     * @param bizProjectBudgetBatch 项目预算主
     * @return 项目预算主
     */
    @Override
    public List<BizProjectBudgetBatch> selectBizProjectBudgetBatchList(BizProjectBudgetBatch bizProjectBudgetBatch)
    {
        QueryWrapper<BizProjectBudgetBatch> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("PROJECT_ID",bizProjectBudgetBatch.getProjectId());
        return projectBudgetBatchMapper.selectList(queryWrapper);
    }

    /**
     * 新增项目预算主
     *
     * @param bizProjectBudgetBatch 项目预算主
     * @param operType
     * @return 结果
     */
    @Override
    public int insertBizProjectBudgetBatch(BizProjectBudgetBatch bizProjectBudgetBatch,String operType)
    {
        if(bizProjectBudgetBatch != null && StringUtils.isNotBlank(bizProjectBudgetBatch.getBudgetFee()) && !operType.equals("apply")){
            bizProjectBudgetBatch.setBudgetFee(Double.toString(Double.parseDouble(bizProjectBudgetBatch.getBudgetFee())*10000));
        }
        return projectBudgetBatchMapper.insert(bizProjectBudgetBatch);
    }

    /**
     * 修改项目预算主
     *
     * @param bizProjectBudgetBatch 项目预算主
     * @param operType
     * @return 结果
     */
    @Override
    public int updateBizProjectBudgetBatch(BizProjectBudgetBatch bizProjectBudgetBatch,String operType)
    {
        if(bizProjectBudgetBatch != null && StringUtils.isNotBlank(bizProjectBudgetBatch.getBudgetFee()) && !operType.equals("apply")){
            bizProjectBudgetBatch.setBudgetFee(Double.toString(Double.parseDouble(bizProjectBudgetBatch.getBudgetFee())*10000));
        }
        return projectBudgetBatchMapper.updateById(bizProjectBudgetBatch);
    }

    /**
     * 批量删除项目预算主
     *
     * @param IDs 需要删除的项目预算主主键
     * @return 结果
     */
    @Override
    public int deleteBizProjectBudgetBatchByIDs(String[] IDs)
    {
        return projectBudgetBatchMapper.deleteBatchIds(Arrays.asList(IDs));
    }

    /**
     * 删除项目预算主信息
     *
     * @param ID 项目预算主主键
     * @return 结果
     */
    @Override
    public int deleteBizProjectBudgetBatchByID(String ID)
    {
        return projectBudgetBatchMapper.deleteById(ID);
    }
    //endregion

    //region 预算从表

    /**
     * 查询项目预算额度(预算从表)
     *
     * @param ID 项目预算额度(预算从表)主键
     * @return 项目预算额度(预算从表)
     */
    @Override
    public BizProjectBudgetFee selectBizProjectBudgetFeeByID(String ID)
    {
        return projectBudgetFeeMapper.selectById(ID);
    }

    /**
     * 查询项目预算额度(预算从表)列表
     *
     * @param bizProjectBudgetFee 项目预算额度(预算从表)
     * @return 项目预算额度(预算从表)
     */
    @Override
    public List<BizProjectBudgetFee> selectBizProjectBudgetFeeList(BizProjectBudgetFee bizProjectBudgetFee)
    {
        QueryWrapper< BizProjectBudgetFee > queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("PROJECT_ID",bizProjectBudgetFee.getProjectId())
                .eq(StringUtils.isNotBlank(bizProjectBudgetFee.getBudgetType()),"BUDGET_TYPE",bizProjectBudgetFee.getBudgetType());
        return projectBudgetFeeMapper.selectList(queryWrapper);
    }

    /**
     * 新增项目预算额度(预算从表)
     *
     * @param bizProjectBudgetFee 项目预算额度(预算从表)
     * @param operType all apply  noBatch
     * @return 结果
     */
    @Override
    public int insertBizProjectBudgetFee(BizProjectBudgetFee bizProjectBudgetFee,String operType)
    {
        if(bizProjectBudgetFee != null && StringUtils.isNotBlank(bizProjectBudgetFee.getSubjectFee()) && operType.equals("all")){
            bizProjectBudgetFee.setSubjectFee(Double.toString(Double.parseDouble(bizProjectBudgetFee.getSubjectFee()) * 10000));
        }
        return projectBudgetFeeMapper.insert(bizProjectBudgetFee);
    }

    /**
     * 修改项目预算额度(预算从表)
     *
     * @param bizProjectBudgetFee 项目预算额度(预算从表)
     * @return 结果
     */
    @Override
    public int updateBizProjectBudgetFee(BizProjectBudgetFee bizProjectBudgetFee)
    {
        return projectBudgetFeeMapper.updateById(bizProjectBudgetFee);
    }

    /**
     * 批量删除项目预算额度(预算从表)
     *
     * @param IDs 需要删除的项目预算额度(预算从表)主键
     * @return 结果
     */
    @Override
    public int deleteBizProjectBudgetFeeByIDs(String[] IDs)
    {
        return projectBudgetFeeMapper.deleteBatchIds(Arrays.asList(IDs));
    }

    /**
     * 删除项目预算额度(预算从表)信息
     *
     * @param ID 项目预算额度(预算从表)主键
     * @return 结果
     */
    @Override
    public int deleteBizProjectBudgetFeeByID(String ID)
    {
        return projectBudgetFeeMapper.deleteById(ID);
    }
    //endregion

    /**
     * 获取新构造的预算信息
     * @param proId
     * @return
     */
    List<BudgetFeeVo> selectBudgetFeeInfo(String proId){
        return projectBudgetFeeMapper.selectBudgetFeeInfo(proId);
    }


    /**
     * 保存预算所有信息
     * @param projectBudgetBo
     * @param operType
     * @return
     */
    public String saveBudgetInfos(ProjectBudgetBo projectBudgetBo,String operType){
        String res = "保存成功！";
        BizProjectBudgetBatch batchInfo = projectBudgetBo.getBizProjectBudgetBatch();
        String batchId = "";
        String feeAll = "";
        String proClass = "";
        if(batchInfo!=null){
            batchId = batchInfo.getID();
            feeAll = batchInfo.getBudgetFee();
            proClass = batchInfo.getProjectClass();
        }
        List<BizProjectBudgetFee> feeList = projectBudgetBo.getBizProjectBudgetFee();

        SysUser loginUser = SecurityUtils.getLoginUser().getUser();
        Date date = new Date();
        SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try{
            if(operType.equals("all") || operType.equals("apply")){
                //all时才处理batch表，否则仅处理fee表
                batchInfo.setBudgetDate(dateFormat.parse(dateFormat.format(date)));
                batchInfo.setLasteditdate(dateFormat.parse(dateFormat.format(date)));
                batchInfo.setLasteditusername(loginUser.getNickName());
                batchInfo.setLastedituserid(loginUser.getUserRealId());

                //先根据项目号获取预算主表id,如果没有数据就是新建预算，如果有就是编辑
                String proId = batchInfo.getProjectId();
                BizProjectBudgetBatch bizProjectBudgetBatch = new BizProjectBudgetBatch();
                bizProjectBudgetBatch.setProjectId(proId);
                List<BizProjectBudgetBatch> batchList = this.selectBizProjectBudgetBatchList(bizProjectBudgetBatch);

                if(batchList != null && batchList.size()>0){
                    //更新预算信息
                    batchId = batchList.get(0).getID();
                    batchInfo.setID(batchId);
                    this.updateBizProjectBudgetBatch(batchInfo,operType);
                }else{
                    //新建预算信息
                    batchInfo.setCreatedate(dateFormat.parse(dateFormat.format(date)));
                    batchInfo.setCreateuserid(loginUser.getUserRealId());
                    batchInfo.setCreateusername(loginUser.getNickName());
                    //生成主键id
                    String uuid = IdUtils.simpleUUID();
                    batchInfo.setID(uuid);
                    int batchRes = this.insertBizProjectBudgetBatch(batchInfo,operType);
                    if(batchRes>0){
                        batchId = uuid;
                    }
                }
            }

            //从表信息先删除，后新建
            String batchIdForProID = batchId;
            if(StringUtils.isNotBlank(batchIdForProID)){
                QueryWrapper<BizProjectBudgetFee> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("BUDGET_BATCH_ID",batchIdForProID);
                projectBudgetFeeMapper.delete(queryWrapper);
                if(StringUtils.isNotBlank(batchIdForProID)){
                    for(int m = 0;m<feeList.size();m++){
                        BizProjectBudgetFee bizProjectBudgetFee = feeList.get(m);
                        bizProjectBudgetFee.setBudgetBatchId(batchIdForProID);

                        //计算费用占比-》不计算了，变更才会影响占比，在变更那里重新计算就好
//                        if(StringUtils.isNotBlank(feeAll) && StringUtils.isNotBlank(proClass) && proClass.equals("xJProject")){
//                            bizProjectBudgetFee.setFeeRatio(this.getNewFeeRatio(feeAll,bizProjectBudgetFee.getSubjectFee()));
//                        }
                        this.insertBizProjectBudgetFee(bizProjectBudgetFee,operType);
                    }
                }
            }else{
                res = "保存预算信息失败！";
            }

        }catch (Exception exception){
            res = "保存失败！" + exception.getMessage();
        }

        return res;

    }

    /**
     * 计算新的百分比
     * @param feeAll
     * @param subFee
     * @return
     */
    private BigDecimal getNewFeeRatio(String feeAll,String subFee){
        double feeRatio = Double.valueOf(subFee)/Double.valueOf(feeAll)*100;
        if (feeRatio < 0) throw new IllegalArgumentException();

        BigDecimal res = BigDecimal.valueOf(feeRatio);
        return res.setScale(2, RoundingMode.HALF_UP); // 四舍五入
    }

    /**
     * 删除预算信息
     * @param proId
     * @return
     */
    public String delBudgetInfos(String proId){
        String res = "删除成功！";
        try{
            //分别删除预算主表和预算从表
            BizProjectBudgetBatch bizProjectBudgetBatch = new BizProjectBudgetBatch();
            bizProjectBudgetBatch.setProjectId(proId);
            List<BizProjectBudgetBatch> batchList = this.selectBizProjectBudgetBatchList(bizProjectBudgetBatch);
            String batchId = "";
            if(batchList != null && batchList.size()>0){
                batchId = batchList.get(0).getID();
                //删除主表
                projectBudgetBatchMapper.deleteById(batchId);

                //删除从表
                QueryWrapper<BizProjectBudgetFee> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("BUDGET_BATCH_ID",batchId);
                projectBudgetFeeMapper.delete(queryWrapper);
            }
        }catch (Exception exception){
            res = "操作失败！" + exception.getMessage();
        }
        return res;
    }

    /**
     * 变更审核后处理预算表（只有校级、纵向有留校预算变更）
     * @param proId 项目号
     * @param alterList 变更表的数据
     * @param proClass 项目类型
     */
    public void changeBudgetInfo(String proId,List<BizProjectBudgetAlteration> alterList,String proClass){
        try{
            //获取总经费，方便后面算占比
            String feeTotal = StringUtils.isNotBlank(proId)?projectBudgetFeeMapper.getFeeTotal(proId):"0";

            //获取原预算数据：feeList是该项目的预算表从表信息，根据项目号获取，每组数据都同时包含liuxiao、peitao、zhuanxiang、zichou、waibo这五种类型
            BizProjectBudgetFee budgetFee = new BizProjectBudgetFee();
            budgetFee.setProjectId(proId);
            List<BizProjectBudgetFee> feeList = this.selectBizProjectBudgetFeeList(budgetFee);
            if(feeList != null && feeList.size() >0 && alterList != null && alterList.size()>0){
                // 构造新的预算数据：留校预算变更，费用变更表里的budgetType必为liuxiao
                // 如果某行数据的subjectCode相同
                // 1:budgetType为liuxiao时-》将变更表中变更后的值赋给预算的费用 -》liuxiao的预算信息变为更改后的值
                // 2:budgetType为zhuangxiaong时-》根据对应code的更改量改专项的值（外拨固定不变）
                // 3:重新计算占比-》subcode是这个的都要重新计算，而且都和专项一致，否则取预算信息会报错

                Map<String,BizProjectBudgetAlteration> alterMap = alterList.stream().
                        collect(Collectors.toMap(BizProjectBudgetAlteration::getSubjectCode,item->item));
                feeList.forEach(feeInfo ->{
                    if(feeInfo.getBudgetType().equals("liuxiao")){
                        String subCode = feeInfo.getSubjectCode();//获取到变更的科目，后面处理专项时也处理科目
                        AtomicReference<String> feeChange = new AtomicReference<>("0");//变更的都是留校，处理留校时获取到变更量
                        AtomicReference<BigDecimal> newRatio = new AtomicReference<>(feeInfo.getFeeRatio());//获取旧的占比，后面专项重新计算后统一给所有该科目的赋值

                        //根据subCode获取变更信息
                        BizProjectBudgetAlteration alterNow = alterMap.get(subCode);
                        if(alterNow != null){
                            feeChange.set(alterNow.getBudgetFeeChange());
                            feeInfo.setSubjectFee(alterNow.getAfterAlterBudgetFee());//将变更表中变更后的值赋给预算的费用
                            feeInfo.setFeeRatio(this.getNewFeeRatio(feeTotal,alterNow.getAfterAlterBudgetFee()));//校级没有专项，校级只有一套留校的数据，所以处理留校的时候先处理了占比，纵向的后面再统一处理
                            if(proClass.equals("zXProject")){
                                feeList.stream()
                                        .filter(newFeeInfo->newFeeInfo.getBudgetType().equals("zhuanxiang")
                                                && newFeeInfo.getSubjectCode().equals(subCode))
                                        .findFirst()
                                        .ifPresent(newFeeInfo -> {
                                            double newZxFee = Double.valueOf(newFeeInfo.getSubjectFee()) + Double.valueOf(feeChange.get());//根据对应留校更改量改专项的值
                                            newFeeInfo.setSubjectFee(Double.toString(newZxFee));
                                            newRatio.set(this.getNewFeeRatio(feeTotal,Double.toString(newZxFee)));
                                            feeList.stream()
                                                    .filter(feeByCode -> feeByCode.getSubjectCode().equals(subCode))
                                                    .forEach(item->item.setFeeRatio(newRatio.get()));
                                        });
                            }

                        }
                    }
                });

                //直接保存新的预算信息
                ProjectBudgetBo projectBudgetBo  = new ProjectBudgetBo();
                projectBudgetBo.setBizProjectBudgetFee(feeList);

                //根据项目号获取batch信息并存入
                BizProjectBudgetBatch bizProjectBudgetBatch = new BizProjectBudgetBatch();
                bizProjectBudgetBatch.setProjectId(proId);
                List<BizProjectBudgetBatch> batchList = this.selectBizProjectBudgetBatchList(bizProjectBudgetBatch);
                if(batchList!=null&& batchList.size()>0){
                    projectBudgetBo.setBizProjectBudgetBatch(batchList.get(0));
                }
                this.saveBudgetInfos(projectBudgetBo,"noBatch");
            }
        }catch (Exception exception){
            String ex = exception.getMessage();
        }
    }
}
